// Package dao
// @Author zhongxc
// @Date 2024/7/19 17:03:00
// @Desc
package dao

import (
	"context"
	"errors"
	"fmt"
	"gorm.io/gorm"
	"strings"
	"vben-admin/pkg/dao/internal"
	"vben-admin/pkg/model"
	"vben-common/msdb"
	"vben-common/msdb/gorms"
)

type RoleDao struct {
	conn    *gorms.GormConn
	columns *internal.RoleColumns
}

func (r *RoleDao) getSession(ctx context.Context) *gorm.DB {
	return r.conn.Session(ctx)
}

// CreateRole
// @Description: 创建角色
// @receiver r
// @param ctx
// @param role
// @return error
func (r *RoleDao) CreateRole(ctx context.Context, role *model.RoleModel) error {
	return r.getSession(ctx).
		Omit(model.IgnoreDeletedAt, model.IgnoreDeletedBy, model.IgnoreUpdatedAt, model.IgnoreUpdatedBy).
		Create(role).
		Error
}

// CreateRoleWithPermissions
// @Description: 创建角色并关联权限
// @receiver r
// @param ctx
// @param role
// @param perms
// @return error
func (r *RoleDao) CreateRoleWithPermissions(ctx context.Context, role *model.RoleModel, perms []*model.RoleMenuModel) error {
	tx := r.getSession(ctx).Begin()
	err := tx.Omit(model.IgnoreDeletedAt, model.IgnoreDeletedBy, model.IgnoreUpdatedAt, model.IgnoreUpdatedBy).Create(role).Error
	if err != nil {
		tx.Rollback()
		return err
	}

	err = tx.Create(perms).Error
	if err != nil {
		tx.Rollback()
		return err
	}

	tx.Commit()
	return nil
}

// UpdateRoleById
// @Description: 根据ID更新角色
// @receiver r
// @param ctx
// @param id
// @param role
// @return error
func (r *RoleDao) UpdateRoleById(ctx context.Context, id int64, role map[string]any) error {
	idField := fmt.Sprintf("%s=?", r.columns.Id)
	err := r.getSession(ctx).Model(&model.RoleModel{}).Where(idField, id).Updates(role).Error
	return err
}

// GetRoleById
// @Description: 根据ID获取角色
// @receiver r
// @param ctx
// @param id
// @return *model.RoleModel
// @return error
func (r *RoleDao) GetRoleById(ctx context.Context, id int64) (*model.RoleModel, error) {
	var role model.RoleModel
	idField := fmt.Sprintf("%s=?", r.columns.Id)
	deletedQuery := fmt.Sprintf("%s=?", r.columns.Deleted)
	err := r.getSession(ctx).Where(deletedQuery, 0).Where(idField, id).First(&role).Error
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, nil
		}
		return nil, err
	}
	return &role, nil
}

// DeleteRoleByIds
// @Description: 根据ID删除角色
// @receiver r
// @param ctx
// @param ids
// @return error
func (r *RoleDao) DeleteRoleByIds(ctx context.Context, ids []int64, data map[string]any) error {
	idQuery := fmt.Sprintf("%s IN ?", r.columns.Id)
	err := r.getSession(ctx).Model(&model.RoleModel{}).
		Where(idQuery, ids).
		Updates(data).
		Error
	return err
}

// GetRoleList
// @Description: 获取角色列表
// @receiver r
// @param ctx
// @param name
// @param status
// @return []*model.RoleModel
// @return error
func (r *RoleDao) GetRoleList(ctx context.Context, roleName string, roleStatus int32) ([]*model.RoleQueryModel, error) {
	if roleStatus < -1 || roleStatus > 1 {
		return nil, errors.New("无效的角色状态")
	}
	var roleList []*model.RoleQueryModel
	nameQuery := fmt.Sprintf("%s LIKE ?", r.columns.Name)
	statusQuery := fmt.Sprintf("%s=?", r.columns.Status)
	deletedQuery := fmt.Sprintf("%s=?", r.columns.Deleted)

	db := r.getSession(ctx).Where(deletedQuery, 0)

	if roleStatus != -1 {
		db.Where(statusQuery, roleStatus)
	}

	if strings.TrimSpace(roleName) != "" {
		db.Where(nameQuery, "%"+roleName+"%")
	}
	db.Joins("LEFT JOIN sys_role_menu ON sys_role_menu.role_id = sys_role.id").Select("sys_role.*,GROUP_CONCAT(sys_role_menu.menu_id) AS menu ")
	db = db.Order(fmt.Sprintf("%s DESC", r.columns.OrderNo))

	// SELECT sys_role.*,GROUP_CONCAT(sys_role_menu.menu_id)  FROM sys_role LEFT JOIN sys_role_menu ON sys_role_menu.role_id = sys_role.id GROUP BY sys_role.id
	db.Group("sys_role.id")

	err := db.Find(&roleList).Error
	return roleList, err
}

// FindByName
// @Description: 根据名称获取角色
// @receiver r
// @param ctx
// @param name
// @return *model.RoleModel
// @return error
func (r *RoleDao) FindByName(ctx context.Context, name string) (*model.RoleModel, error) {
	var role *model.RoleModel
	err := r.getSession(ctx).
		Where(fmt.Sprintf("%s=?", r.columns.Name), name).
		Where(fmt.Sprintf("%s=?", r.columns.Deleted), 0).
		First(&role).
		Error
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, nil
		}
		return nil, err
	}
	return role, nil
}

// FindByCode
// @Description: 根据编码获取角色
// @receiver r
// @param ctx
// @param code
// @return *model.RoleModel
// @return error
func (r *RoleDao) FindByCode(ctx context.Context, code string) (*model.RoleModel, error) {
	var role *model.RoleModel
	err := r.getSession(ctx).
		Where(fmt.Sprintf("%s=?", r.columns.Code), code).
		Where(fmt.Sprintf("%s=?", r.columns.Deleted), 0).
		First(&role).
		Error
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, nil
		}
		return nil, err
	}
	return role, nil
}

// DeleteRoleMenuTX
// @Description: 删除角色菜单关联（事务）
// @receiver r
// @param ctx
// @param roleId
// @param data
// @return error
func (r *RoleDao) DeleteRoleMenuTX(ctx context.Context, roleId []int64, data map[string]any) error {
	tx := r.getSession(ctx).Begin()
	// 删除角色
	err := tx.Model(&model.RoleModel{}).
		Where(fmt.Sprintf("%s IN ?", r.columns.Id), roleId).
		Updates(data).
		Error

	if err != nil {
		tx.Rollback()
		return err
	}

	// 删除角色菜单关联
	err = tx.Where("role_id IN ?", roleId).Delete(&model.RoleMenuModel{}).Error
	if err != nil {
		tx.Rollback()
		return err
	}

	tx.Commit()
	return nil
}

func NewRoleDao(db *msdb.MsDB) *RoleDao {
	return &RoleDao{
		conn:    gorms.New(db.Conn),
		columns: internal.NewRoleColumns(),
	}
}
